#include "../include/SkyBox.h"

SkyBox::SkyBox(std::string sbFileName, GLuint shaderProg) {
    shaderProg = shaderProg;
	/*Initialised the scaling factors*/
	scaleX = 0.0;
	scaleY = 0.0;
	scaleZ = 0.0;

	/*Initialise the Image arrays*/
    topImage = new GLubyte[1024*1024*3];
    farImage = new GLubyte[1024*1024*3];
    bottomImage = new GLubyte[1024*1024*3];
    rearImage = new GLubyte[1024*1024*3];
    leftImage = new GLubyte[1024*1024*3];
    rightImage = new GLubyte[1024*1024*3];

	skyFileName = sbFileName;
	texID = new GLuint[6];

    skyBoxImage = new sf::Image();
	/*If the file does not load, Exit the program (Change later to print debug message)*/
    if( !skyBoxImage->loadFromFile(sbFileName))
		exit(-1);

	glGenTextures(6,texID);
	loadSkyBoxImages(); //Load the skybox images into their arrays
    delete skyBoxImage;

    glBindTexture(GL_TEXTURE_2D, texID[0]);
    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
    configTexture();
    glTexImage2D(GL_TEXTURE_2D,0,GL_RGB,1024,1024,0,GL_RGB, GL_UNSIGNED_BYTE,topImage );
    glBindTexture(GL_TEXTURE_2D, texID[1]);
    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
    configTexture();
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB,1024,1024,0, GL_RGB, GL_UNSIGNED_BYTE,farImage );
    glBindTexture(GL_TEXTURE_2D, texID[2]);
    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
    configTexture();
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB,1024,1024,0, GL_RGB, GL_UNSIGNED_BYTE,bottomImage );
    glBindTexture(GL_TEXTURE_2D, texID[3]);
    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
    configTexture();
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB,1024,1024,0, GL_RGB, GL_UNSIGNED_BYTE,rearImage );
    glBindTexture(GL_TEXTURE_2D, texID[4]);
    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
    configTexture();
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB,1024,1024,0, GL_RGB, GL_UNSIGNED_BYTE,leftImage );
    glBindTexture(GL_TEXTURE_2D, texID[5]);
    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
    configTexture();
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB,1024,1024,0, GL_RGB, GL_UNSIGNED_BYTE,rightImage );
}

SkyBox::~SkyBox(){
    delete[] topImage;
    delete[] farImage;
    delete[] bottomImage;
    delete[] rearImage;
    delete[] leftImage;
    delete[] rightImage;
    delete[] texID;
}

void SkyBox::render(){
	glUseProgram(shaderProg);
	glPushMatrix();
    glPushAttrib(GL_ENABLE_BIT);
    glEnable(GL_TEXTURE_2D);
	glScalef(scaleX,scaleY,scaleZ);
    drawCube();
    glDisable(GL_TEXTURE_2D);
    glPopAttrib();
	glPopMatrix();
}

void SkyBox::setScale(GLfloat x, GLfloat y, GLfloat z){
	scaleX = x;
	scaleY = y;
	scaleZ = z;
}

void SkyBox::loadSkyBoxImages(){
	//For Each image, put all the pixels into the correct array
    for(int pixelY = 0; pixelY < 1024 ; pixelY++ ){
        for(int pixelX = 0; pixelX < 1024; pixelX++){
			//Top
            topImage[(pixelX*3) + (pixelY*1024*3)] = (GLubyte)skyBoxImage->getPixel(pixelX+1024,pixelY).r;
            topImage[(pixelX*3) + (pixelY*1024*3) + 1] = (GLubyte)skyBoxImage->getPixel((pixelX)+1024,pixelY).g;
            topImage[(pixelX*3) + (pixelY*1024*3) + 2] = (GLubyte)skyBoxImage->getPixel(pixelX+1024,pixelY).b;
			//Left
            leftImage[(pixelX*3) + (pixelY*1024*3)] = (GLubyte)skyBoxImage->getPixel(pixelX,pixelY+1024).r;
            leftImage[(pixelX*3) + (pixelY*1024*3) + 1] = (GLubyte)skyBoxImage->getPixel(pixelX,pixelY+1024).g;
            leftImage[(pixelX*3) + (pixelY*1024*3) + 2] = (GLubyte)skyBoxImage->getPixel(pixelX,pixelY+1024).b;
			//Far
            farImage[(pixelX*3) + (pixelY*1024*3)] = (GLubyte)skyBoxImage->getPixel(pixelX+1024,pixelY+1024).r;
            farImage[(pixelX*3) + (pixelY*1024*3) + 1] = (GLubyte)skyBoxImage->getPixel(pixelX+1024,pixelY+1024).g;
            farImage[(pixelX*3) + (pixelY*1024*3) + 2] = (GLubyte)skyBoxImage->getPixel(pixelX+1024,pixelY+1024).b;
			//Right
            rightImage[(pixelX*3) + (pixelY*1024*3)] = (GLubyte)skyBoxImage->getPixel(pixelX+2048,pixelY+1024).r;
            rightImage[(pixelX*3) + (pixelY*1024*3) + 1] = (GLubyte)skyBoxImage->getPixel(pixelX+2048,pixelY+1024).g;
            rightImage[(pixelX*3) + (pixelY*1024*3) + 2] = (GLubyte)skyBoxImage->getPixel(pixelX+2048,pixelY+1024).b;
			//Rear
            rearImage[(pixelX*3) + (pixelY*1024*3)] = (GLubyte)skyBoxImage->getPixel(pixelX+3072,pixelY+1024).r;
            rearImage[(pixelX*3) + (pixelY*1024*3) + 1] = (GLubyte)skyBoxImage->getPixel(pixelX+3072,pixelY+1024).g;
            rearImage[(pixelX*3) + (pixelY*1024*3) + 2] = (GLubyte)skyBoxImage->getPixel(pixelX+3072,pixelY+1024).b;
			//Bottom
            bottomImage[(pixelX*3) + (pixelY*1024*3)] = (GLubyte)skyBoxImage->getPixel(pixelX+1024,pixelY+2048).r;
            bottomImage[(pixelX*3) + (pixelY*1024*3) + 1] = (GLubyte)skyBoxImage->getPixel(pixelX+1024,pixelY+2048).g;
            bottomImage[(pixelX*3) + (pixelY*1024*3) + 2] = (GLubyte)skyBoxImage->getPixel(pixelX+1024,pixelY+2048).b;
		}
    }
}

void SkyBox::configTexture() {
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
}

/* Private method for drawing a Cube for the skybox. Size = 1x1
 * Also sets texture co-ords
 */
void SkyBox::drawCube(){
    CG::bindTexture(texID[0], GL_TEXTURE0);
	glBegin(GL_QUADS);
	// Top
	//glNormal3f(0,-1,0);
	glTexCoord2f(0, 0); glVertex3f(-0.5,0.5,0.5);
	glTexCoord2f(0, 1); glVertex3f(-0.5,0.5,-0.5);
	glTexCoord2f(1, 1); glVertex3f(0.5,0.5,-0.5);
	glTexCoord2f(1, 0); glVertex3f(0.5,0.5,0.5);
	glEnd();

    CG::bindTexture(texID[1], GL_TEXTURE0);
    glBegin(GL_QUADS);
	// Far
	//glNormal3f(0,0,1);
	glTexCoord2f(0, 0); glVertex3f(-0.5,0.5,-0.5);
	glTexCoord2f(0, 1); glVertex3f(-0.5,-0.5,-0.5);
	glTexCoord2f(1, 1); glVertex3f(0.5,-0.5,-0.5);
	glTexCoord2f(1, 0); glVertex3f(0.5,0.5,-0.5);
	glEnd();

    CG::bindTexture(texID[2], GL_TEXTURE0);
    glBegin(GL_QUADS);
	// Bottom
	//glNormal3f(0,1,0);
	glTexCoord2f(0, 0); glVertex3f(-0.5,-0.5,-0.5);
	glTexCoord2f(0, 1); glVertex3f(-0.5,-0.5,0.5);
	glTexCoord2f(1, 1); glVertex3f(0.5,-0.5,0.5);
	glTexCoord2f(1, 0); glVertex3f(0.5,-0.5,-0.5);
	glEnd();

    CG::bindTexture(texID[3], GL_TEXTURE0);
    glBegin(GL_QUADS);
    //Rear
    //glNormal3f(0,0,-1);
    glTexCoord2f(1, 0); glVertex3f(-0.5,0.5,0.5);
    glTexCoord2f(0, 0); glVertex3f(0.5,0.5,0.5);
    glTexCoord2f(0, 1); glVertex3f(0.5,-0.5,0.5);
    glTexCoord2f(1, 1); glVertex3f(-0.5,-0.5,0.5);
    glEnd();

    CG::bindTexture(texID[4], GL_TEXTURE0);
    glBegin(GL_QUADS);
    //Left
    //glNormal3f(1,0,0);
    glTexCoord2f(0, 0); glVertex3f(-0.5,0.5,0.5);
    glTexCoord2f(0, 1); glVertex3f(-0.5,-0.5,0.5);
    glTexCoord2f(1, 1); glVertex3f(-0.5,-0.5,-0.5);
    glTexCoord2f(1, 0); glVertex3f(-0.5,0.5,-0.5);
    glEnd();

    CG::bindTexture(texID[5], GL_TEXTURE0);
    glBegin(GL_QUADS);
	//Right
	//glNormal3f(-1,0,0);
	glTexCoord2f(0, 0); glVertex3f(0.5,0.5,-0.5);
	glTexCoord2f(0, 1);  glVertex3f(0.5,-0.5,-0.5);
	glTexCoord2f(1, 1); glVertex3f(0.5,-0.5,0.5);
	glTexCoord2f(1, 0); glVertex3f(0.5,0.5,0.5);
	glEnd();
}
